﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace AdTech.Snap
{
    /// <summary>
    /// Represents the converter that converts a <see cref="System.Windows.Media.SolidColorBrush"/> to and from 
    /// <see cref="System.Collections.Generic.KeyValuePair&lt;TKey,TValue&gt;"/>.
    /// </summary>
    [ValueConversion(typeof(SolidColorBrush), typeof(KeyValuePair<string, SolidColorBrush>))]
    public class BrushConverter : IValueConverter
    {
        // Properties
        /// <summary>
        /// Gets a list of Brushes associated with their display names.
        /// </summary>
        public Dictionary<string, SolidColorBrush> Brushes { get; private set; }

        // Constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="AdTech.Snap.BrushConverter"/> class.
        /// </summary>
        public BrushConverter()
        {
            this.Brushes = typeof(Brushes)
                .GetProperties(BindingFlags.Public | BindingFlags.Static)
                .Where(x => x.PropertyType == typeof(SolidColorBrush))
                .ToDictionary(x => x.Name, y => ((SolidColorBrush)y.GetValue(null, null)).Clone());
        }

        #region IValueConverter Members
        /// <summary>
        /// Converts a <see cref="System.Windows.Media.SolidColorBrush"/> to a 
        /// <see cref="System.Collections.Generic.KeyValuePair&lt;TKey,TValue&gt;"/>
        /// of the actual brush and its display name.
        /// </summary>
        /// <param name="value">A <see cref="System.Windows.Media.SolidColorBrush"/>.</param>
        /// <param name="targetType">This parameter is not used.</param>
        /// <param name="parameter">This parameter is not used.</param>
        /// <param name="culture">This parameter is not used.</param>
        /// <returns>
        /// The <see cref="System.Collections.Generic.KeyValuePair&lt;TKey,TValue&gt;"/> 
        /// otherwise null if the input value was not of type <see cref="System.Windows.Media.SolidColorBrush"/> 
        /// or not found in the <see cref="System.Windows.Media.Brushes"/> type.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            SolidColorBrush brush = value as SolidColorBrush;
            if (brush == null)
                return null;

            return this.Brushes.FirstOrDefault(x => x.Value.Color.Equals(brush.Color));
        }

        /// <summary>
        /// Converts a <see cref="System.Collections.Generic.KeyValuePair&lt;TKey,TValue&gt;"/> to a 
        /// <see cref="System.Windows.Media.SolidColorBrush"/>.
        /// </summary>
        /// <param name="value">A <see cref="System.Collections.Generic.KeyValuePair&lt;TKey,TValue&gt;"/>.</param>
        /// <param name="targetType">This parameter is not used.</param>
        /// <param name="parameter">This parameter is not used.</param>
        /// <param name="culture">This parameter is not used.</param>
        /// <returns>The <see cref="System.Windows.Media.SolidColorBrush"/>.</returns>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null)
                return null;

            KeyValuePair<string, SolidColorBrush> item = (KeyValuePair<string, SolidColorBrush>)value;
            return item.Value;
        }
        #endregion
    }

    /// <summary>
    /// Represents the converter that converts a <see cref="System.Windows.Media.SolidColorBrush"/> from and to string.
    /// </summary>
    [ValueConversion(typeof(string), typeof(KeyValuePair<string, SolidColorBrush>))]
    public class BrushNameConverter : IValueConverter
    {
        // Properties
        /// <summary>
        /// Gets a list of Brushes associated with their display names.
        /// </summary>
        public Dictionary<string, SolidColorBrush> Brushes { get; private set; }

        // Constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="AdTech.Snap.BrushNameConverter"/> class.
        /// </summary>
        public BrushNameConverter()
        {
            this.Brushes = typeof(Brushes)
                .GetProperties(BindingFlags.Public | BindingFlags.Static)
                .Where(x => x.PropertyType == typeof(SolidColorBrush))
                .ToDictionary(x => x.Name, y => ((SolidColorBrush)y.GetValue(null, null)).Clone());
        }

        #region IValueConverter Members
        /// <summary>
        /// Converts the display name of a brush to a 
        /// <see cref="System.Collections.Generic.KeyValuePair&lt;TKey,TValue&gt;"/>
        /// of the actual brush and its display name.
        /// </summary>
        /// <param name="value">The display name of the brush.</param>
        /// <param name="targetType">This parameter is not used.</param>
        /// <param name="parameter">This parameter is not used.</param>
        /// <param name="culture">This parameter is not used.</param>
        /// <returns>
        /// The <see cref="System.Collections.Generic.KeyValuePair&lt;TKey,TValue&gt;"/> 
        /// otherwise null if the input value was empty or not found in the <see cref="System.Windows.Media.Brushes"/> type.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string name = value as string;
            if (String.IsNullOrEmpty(name))
                return null;

            return this.Brushes.FirstOrDefault(x => x.Key.Equals(name));
        }

        /// <summary>
        /// Converts <see cref="System.Collections.Generic.KeyValuePair&lt;TKey,TValue&gt;"/> to its display name.
        /// </summary>
        /// <param name="value">A <see cref="System.Collections.Generic.KeyValuePair&lt;TKey,TValue&gt;"/>.</param>
        /// <param name="targetType">This parameter is not used.</param>
        /// <param name="parameter">This parameter is not used.</param>
        /// <param name="culture">This parameter is not used.</param>
        /// <returns>The display name.</returns>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null)
                return null;

            KeyValuePair<string, SolidColorBrush> item = (KeyValuePair<string, SolidColorBrush>)value;
            return item.Key;
        }
        #endregion
    }

    /// <summary>
    /// Represents the converter that converts a <see cref="ReadOnlyObservableCollection&lt;ValidationError&gt;"/> to string.
    /// </summary>
    [ValueConversion(typeof(int), typeof(string))]
    public sealed class DropboxUIDConverter : IValueConverter
    {
        #region IValueConverter Members
        /// <summary>
        /// Converts a Dropbox UserID result into a readable form.
        /// </summary>
        /// <param name="value">The Dropbox UserID.</param>
        /// <param name="targetType">This parameter is not used.</param>
        /// <param name="parameter">This parameter is not used.</param>
        /// <param name="culture">This parameter is not used.</param>
        /// <returns>
        /// A result string.
        /// </returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null)
                return Binding.DoNothing;

            int uid = (int)value;
            return uid > 0 ? String.Format("Successfully extracted UserID: {0}", uid) : "Waiting for clipboard changes";
        }

        /// <summary>
        /// This method is not implemented.
        /// </summary>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
        #endregion
    }

    /// <summary>
    /// Represents the converter that converts a <see cref="ReadOnlyObservableCollection&lt;ValidationError&gt;"/> to string.
    /// </summary>
    [ValueConversion(typeof(ReadOnlyObservableCollection<ValidationError>), typeof(string))]
    public sealed class ValidationErrorsToStringConverter : IMultiValueConverter
    {
        #region IValueConverter Members
        /// <summary>
        /// Converts the <see cref="ReadOnlyObservableCollection&lt;ValidationError&gt;"/>
        /// containing validation errors to a readable string.
        /// </summary>
        /// <param name="values">The validation error collection.</param>
        /// <param name="targetType">This parameter is not used.</param>
        /// <param name="parameter">This parameter is not used.</param>
        /// <param name="culture">This parameter is not used.</param>
        /// <returns>
        /// A string of validation errors concatenated by a NewLine character.
        /// </returns>
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            ReadOnlyObservableCollection<ValidationError> errors = values[0] as ReadOnlyObservableCollection<ValidationError>;
            return String.Join(Environment.NewLine, errors.Select(x => x.ErrorContent).OfType<string>().ToArray());
        }

        /// <summary>
        /// This method is not implemented.
        /// </summary>
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}
